package com.gcloud.mesh.dcs.task;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.constant.DictCode;
import org.jeecg.common.system.vo.DictModel;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.system.entity.SysDict;
import org.jeecg.modules.system.entity.SysDictItem;
import org.jeecg.modules.system.mapper.SysDictItemMapper;
import org.jeecg.modules.system.mapper.SysDictMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gcloud.mesh.alert.consts.RedisKeyConsts.RedisKey;
import com.gcloud.mesh.asset.dao.CloudResourceConfigDao;
import com.gcloud.mesh.asset.dao.CloudResourceDao;
import com.gcloud.mesh.asset.dao.DatacenterDao;
import com.gcloud.mesh.asset.dao.IaasDao;
import com.gcloud.mesh.asset.entity.CloudResourceConfigEntity;
import com.gcloud.mesh.asset.entity.CloudResourceEntity;
import com.gcloud.mesh.asset.entity.DatacenterEntity;
import com.gcloud.mesh.asset.service.ICloudResourceService;
import com.gcloud.mesh.dcs.dao.AppDao;
import com.gcloud.mesh.dcs.dao.AppInstanceDao;
import com.gcloud.mesh.dcs.dao.ModelScoreDao;
import com.gcloud.mesh.dcs.dao.SchedulerConfigDao;
import com.gcloud.mesh.dcs.dao.SchedulerJobDao;
import com.gcloud.mesh.dcs.entity.AppInstanceEntity;
import com.gcloud.mesh.dcs.entity.SchedulerAdviceEntity;
import com.gcloud.mesh.dcs.entity.SchedulerConfigEntity;
import com.gcloud.mesh.dcs.enums.SchedulerAdviceStatus;
import com.gcloud.mesh.dcs.enums.SchedulerModelDict;
import com.gcloud.mesh.dcs.enums.SchedulerModelType;
import com.gcloud.mesh.dcs.service.AppService;
import com.gcloud.mesh.dcs.service.SchedulerAdviceService;
import com.gcloud.mesh.dcs.service.SchedulerService;
import com.gcloud.mesh.distributedSchedule.ICluster;
import com.gcloud.mesh.distributedSchedule.IDistributedSchedule;
import com.gcloud.mesh.distributedSchedule.UpdateClusterResourceTask;
import com.gcloud.mesh.distributedSchedule.application.CommonApplication;
import com.gcloud.mesh.distributedSchedule.scheduler.HighEfficientScheduler;
import com.gcloud.mesh.distributedSchedule.scheduler.Scheduler;
import com.gcloud.mesh.header.enums.ModelType;
import com.gcloud.mesh.header.enums.MonitorMeter;
import com.gcloud.mesh.header.vo.dcs.AppInstanceVo;
import com.gcloud.mesh.header.vo.dcs.AppVo;
import com.gcloud.mesh.header.vo.dcs.PageModelScoreVo;
import com.gcloud.mesh.header.vo.dcs.SchedulerStrategyRuleVo;
import com.gcloud.mesh.monitor.service.StatisticsCheatService;
import com.gcloud.mesh.redis.MockRedis;
import com.gcloud.mesh.supplier.dao.SupplierDao;
import com.gcloud.mesh.supplier.enums.SystemType;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class CheckSchedulerThresholdTask {

	@Autowired
	private SchedulerService schedulerService;

	private IDistributedSchedule distributedScheduleService;

	@Autowired
	private SchedulerConfigDao schedulerConfigDao;

	@Autowired
	private SchedulerJobDao schedulerJobDao;

	@Autowired
	private SchedulerAdviceService adviceService;

	@Autowired
	private AppInstanceDao appInstanceDao;

	@Autowired
	private StatisticsCheatService statisticsCheatService;

	@Autowired
	private AppDao appDao;

	@Autowired
	private MockRedis<Object> redis;

	@Autowired
	private DatacenterDao datacenterDao;

	@Autowired
	private CloudResourceDao cloudResourceDao;
	@Autowired
	private CloudResourceConfigDao cloudResourceConfigDao;

	@Autowired
	private SysDictMapper sysDictMapper;

	@Autowired
	private SysDictItemMapper sysDictItemMapper;

	@Autowired
	private ModelScoreDao modelScoreDao;

	@Autowired
	private ICloudResourceService cloudResourceService;

	@Autowired
	private IaasDao iaasDao;

	@Autowired
	private SupplierDao supplierDao;

	@Autowired
	private RedisUtil redisUtil;
	
	@Autowired
	private ModelScoreDao ModelScoreDao;
	@Autowired
	private AppService appService;

	@Scheduled(fixedDelay = 1000 * 60)
	public void work() {
		log.info("[CheckSchedulerThreshold] 调度阈值检查定时器开始");

		SchedulerStrategyRuleVo ruleVo = schedulerService.getSchedulerStrategyRule();
		String rule = ruleVo.getRule();
		JSONObject json = JSONObject.parseObject(rule);
		int cooling = json.getIntValue("cooling");
		String beginTime = json.getString("beginTime");
		String endTime = json.getString("endTime");

		// 冷却时间范围外
		// //TODO mo 上线需要删除
		// redis.delete(RedisKey.SCHEDULER_COOLING);

		if (redis.getValue(RedisKey.SCHEDULER_COOLING) != null) {
			log.info("[CheckSchedulerThreshold] 调度冷却中");
		} else {

			// 生效时间范围内
			if (isTimeRange(beginTime, endTime)) {

				for(SchedulerModelType type : SchedulerModelType.getSchedulerModelType()) {
					//删除原来还没启动的建议
					 adviceService.deleteByReadyStatus(type.getValue());
						Map<String,Integer> appScore = modelScoreDao.getAppScore();
						Map<String, Double> datacenterScores = schedulerConfigDao.getDatacenterAppScore();
						// 查找所有监控策略 dcs_scheduler_configs
						List<SchedulerConfigEntity> configs = schedulerConfigDao.findByProperty("thresholdKey",type.name());
						if (configs != null) {
							for (SchedulerConfigEntity config : configs) {
								ModelType modeType = ModelType.get(config.getThresholdKey());
								Double datacenterScore = datacenterScores.get(config.getDatacenterId());
								double dataAppScore = datacenterScore == null ? 0:datacenterScore; 
								List<PageModelScoreVo> modelScores = modelScoreDao.getPageOrderByTime(
										modeType, config.getDatacenterId(),
										PageModelScoreVo.class);
								if (modelScores == null || modelScores.size() == 0) {
									continue;
								}
								int score = modelScores.get(0).getTotalScore();
								double thresholdValue = config.getThresholdValue();
								if (score < thresholdValue) {
									List<CloudResourceEntity> cloudResouces = cloudResourceDao.findByProperty("datacenter_id", config.getDatacenterId());
									for (CloudResourceEntity entity : cloudResouces) {
										List<AppVo> apps = appDao.getByResourceId(entity.getId());
			
										if (apps == null || apps.isEmpty())
											continue;
										if (SystemType.getSystemTypeByNo(entity.getType()) == SystemType.K8S) {
											// 与监控策略做比较（根据数据中心id获取gce集群数据）
											// 查询出所有的应用
											log.info("[CheckSchedulerThreshold] checkSchedulerJob Start. Datacenter: "
													+ config.getDatacenterId());
			
			//								PageResult<PageModelScoreVo> modelScores = modelScoreDao.getPage4Migration(
			//										supplierEntity.getType(),
			//										ModelType.get(SchedulerModelDict.get(sysDictItem.getItemValue()).name()), 1,
			//										Integer.MAX_VALUE, null, null, PageModelScoreVo.class);
			
											log.info("[CheckSchedulerThreshold] modelScores list start");
			//								for (int i = 1; i <= modelScores.getList().size(); i++) {
			//									PageModelScoreVo vo = modelScores.getList().get(i - 1);
			//									log.info("[CheckSchedulerThreshold] scoreNumber: 【" + i + "】. deviceId: "
			//											+ vo.getResourceId() + ". score:" + vo.getTotalScore() + ". datacenterId:"
			//											+ vo.getDatacenterId());
			//								}
			
											log.info("[CheckSchedulerThreshold] modelScores list end");
			
											for (AppVo app : apps) {
												Integer appcurrentScore = appScore.get(app.getId());
												if(appcurrentScore != null && appcurrentScore < dataAppScore) {
													doExce(app, modelScores, entity, modeType);
												}
											}
											log.info("[CheckSchedulerThreshold] checkSchedulerJob End. Datacenter: "
													+ config.getDatacenterId());
			
										} else {
											// 虚拟机同步
			//								PageResult<PageModelScoreVo> modelScores = modelScoreDao.getPage4Migration(
			//										supplierEntity.getType(),
			//										ModelType.get(SchedulerModelDict.get(sysDictItem.getItemValue()).name()), 1,
			//										Integer.MAX_VALUE, null, null, PageModelScoreVo.class);
											
											for (AppVo app : apps) {
												config.setDatacenterId(app.getId());
												Integer appcurrentScore = appScore.get(app.getId());
												if(appcurrentScore != null && appcurrentScore < dataAppScore) {
													doExce(app, modelScores, entity, modeType);
												}
											}
			
										}
									}
			
									adviceService.moveAdviceToJop();
								} else {
									log.info("[CheckSchedulerThreshold] No datacenter to be scheduled was found!");
								}
							}
						} else {
							log.info("[CheckSchedulerThreshold] Scheduler policy not found!");
						}
						redis.setValue(RedisKey.SCHEDULER_COOLING, true);
						redis.updateTimeout(RedisKey.SCHEDULER_COOLING, (long) (cooling * 60));
				}

			} else {
				log.info("[CheckSchedulerThreshold] Not in policy time frame!");
			}
		}

		log.info("[CheckSchedulerThreshold] 调度阈值检查定时器结束");
	}

	private void doExce(AppVo app, List<PageModelScoreVo> modelScores,
			CloudResourceEntity cloudResource, ModelType modelType) {
		CommonApplication application = new CommonApplication(app.getName(), app.getId());
		application.setClusterId(app.getDatacenterId());

		// 初始化并更新应用数据
		initApplication(application);

		// 这里先改成获取到的数据中心
		DatacenterEntity datacenterEntity = datacenterDao.getById(app.getDatacenterId());
		// CloudResourceEntity cloudResource = cloudResourceMap.get(app.getCloudResourceId());
		List<CloudResourceConfigEntity> dstdatacenters = cloudResourceConfigDao
				.getSameTypeDatacenterId(cloudResource.getType(), app.getCloudResourceId(), datacenterEntity.getStructure());
		String destClusterId = null;
		String destResourceId = null;
		Map<String, String> centerResourceMap = new HashMap<>();
		if (dstdatacenters == null || dstdatacenters.isEmpty()) {
			log.error("[CheckSchedulerThreshold] 无可用的数据中心迁移");
		} else {
			//筛选出最优的数据中心
			StringBuffer datacenterIds = new StringBuffer(); 
			for(int i = 0;i<dstdatacenters.size();i++) {
				centerResourceMap.put(dstdatacenters.get(i).getDatacenterId(), dstdatacenters.get(i).getCloudResourceId());
				if(i == (dstdatacenters.size()-1)) {
					datacenterIds.append("'").append(dstdatacenters.get(i).getDatacenterId()).append("'");
				}else {
					datacenterIds.append("'").append(dstdatacenters.get(i).getDatacenterId()).append("'").append(",");
				}
			}
			destClusterId  = ModelScoreDao.getBestScoreCenter(modelType, datacenterIds.toString());
			//如果本身的评分最高则不触发
			if(StringUtils.isBlank(destClusterId) || app.getDatacenterId().equals(destClusterId)) {
				log.error("[CheckSchedulerThreshold] 无可用的数据中心迁移");
				return;
			}
			// destClusterId = dstdatacenters.get(0).getDatacenterId();
			destResourceId = centerResourceMap.get(destClusterId);
		}

		// 迁移工具选择
		int tool = 0;
		if (cloudResource.getType().equals(SystemType.HUAWEI.getNo())) {
			tool = 2;
		} else if (cloudResource.getType().equals(SystemType.ALI.getNo())) {
			tool = 1;
		}
		// 迁移模型选择
		int model = SchedulerModelType.getByName(modelType.name()).getValue();
//		List<DictModel> models = sysDictMapper.queryDictItemsByCode(DictCode.SCHEDULER_MODEL.getCode());
//		if (models != null) {
//			for (DictModel value : models) {
//				mode = Integer.parseInt(value.getValue());
//			}
//		}
		// 迁移配置
		int schConfig = 0;
		List<DictModel> configs = sysDictMapper.queryDictItemsByCode(DictCode.SCHEDULER_STRATEGY_CONFIG.getCode());
		if (configs != null) {
			for (DictModel value : configs) {
				schConfig = Integer.parseInt(value.getValue());
			}
		}
		// 获取目标数据中心 end
		// TODO 调度到目标集群
		if (StringUtils.isNotBlank(destClusterId)) {
			// 查出app所有的实例
			List<AppInstanceVo> entityInstances = appService.detail(app.getId()).getInstances();
			List<SchedulerAdviceEntity> entitys = new ArrayList<>();
			for (AppInstanceVo instance : entityInstances) {
				List<SchedulerAdviceEntity> entitysdb = adviceService.listByAppId(app.getId(), app.getCloudResourceId(), instance.getInstanceId(), model);
				if (entitysdb == null || entitysdb.isEmpty()) {
					if(!app.getCloudResourceId().equals(instance.getResourceId())) {
						//代表已经迁移的，不放在建议里面
						continue;
					}
					SchedulerAdviceEntity entity = new SchedulerAdviceEntity();
					entity.setAppId(app.getId());
					entity.setAppName(app.getName());
					entity.setCloudResourceId(cloudResource.getId());
					entity.setCloudResourceName(cloudResource.getName());
					entity.setCloudResourceType(cloudResource.getType());
					entity.setDstDatacenterId(destClusterId);
					entity.setStatus(SchedulerAdviceStatus.READY.getValue());
					entity.setInstanceId(instance.getInstanceId());
					entity.setInstanceName(instance.getInstanceName());
					entity.setDstDatacenterId(destClusterId);
					entity.setSrcDatacenterId(app.getDatacenterId());
					entity.setCreateTime(new Date());
					entity.setSchedulerModelTool(tool);
					entity.setSchedulerModel(model);
					entity.setSchedulerStrategyConfig(schConfig);
					entity.setDstCloudResourceId(destResourceId);
					entitys.add(entity);
				}
				
			}
			adviceService.savebatchAdvice(entitys);
		} else {
			log.info("[CheckSchedulerThreshold] Have PROGRESS or READY state schedulerJob!");
		}

		
	}

	private IDistributedSchedule getDistributedScheduleMode() {
		// TODO 目前只提供高效能的调度算法
		distributedScheduleService = new HighEfficientScheduler(0);

		// 初始化集群资源
		Scheduler schduler = UpdateClusterResourceTask.schduler;
		if (schduler != null) {
			for (ICluster cluster : schduler.getClusterMap().values()) {
				try {
					distributedScheduleService.addCluster(cluster);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}

		return distributedScheduleService;
	}

	private void initApplication(CommonApplication application) {

		int cpuCore = 0, memSpaceG = 0, storageSpaceG = 0, bandWidthKBPS = 0;
		String cpuCoresStr = statisticsCheatService.latestSample(MonitorMeter.APP_CORES.getMeter(),
				application.getAppId());
		String memSpaceGStr = statisticsCheatService.latestSample(MonitorMeter.APP_MEMORY_USAGE.getMeter(),
				application.getAppId());
		String storageSpaceGStr = statisticsCheatService.latestSample(MonitorMeter.APP_STORAGE_USAGE.getMeter(),
				application.getAppId());
		String bandWidthKBPStr = statisticsCheatService.latestSample(MonitorMeter.APP_BANDWIDTH.getMeter(),
				application.getAppId());

		if (!cpuCoresStr.isEmpty()) {
			cpuCore = (int) Double.parseDouble(cpuCoresStr);
		}
		if (!memSpaceGStr.isEmpty()) {
			memSpaceG = (int) Double.parseDouble(memSpaceGStr);
		}
		if (!storageSpaceGStr.isEmpty()) {
			storageSpaceG = (int) Double.parseDouble(storageSpaceGStr);
		}
		if (!bandWidthKBPStr.isEmpty()) {
			bandWidthKBPS = (int) Double.parseDouble(bandWidthKBPStr);
		}

		application.init(cpuCore, memSpaceG, storageSpaceG, bandWidthKBPS);
		application.updateStatus(cpuCore, memSpaceG, storageSpaceG, bandWidthKBPS);
	}

	private boolean isTimeRange(String beginTimeStr, String endTimeStr) {
		SimpleDateFormat df = new SimpleDateFormat("HH:mm");
		try {
			Date now = df.parse(df.format(new Date()));
			Date begin = df.parse(beginTimeStr);
			Date end = df.parse(endTimeStr);
			Calendar nowTime = Calendar.getInstance();
			nowTime.setTime(now);
			Calendar beginTime = Calendar.getInstance();
			beginTime.setTime(begin);
			Calendar endTime = Calendar.getInstance();
			endTime.setTime(end);
			if (nowTime.before(endTime) && nowTime.after(beginTime)) {
				return true;
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return false;
	}
	
	
}
